package ch.ethz.inf.shop.model.simpleDatabase.operators;

import java.util.ArrayList;
import java.util.List;

import ch.ethz.inf.shop.model.simpleDatabase.Tuple;
import ch.ethz.inf.shop.model.simpleDatabase.TupleSchema;

public class LeftJoin extends Operator {

	private final ArrayList<Tuple> leftBuffer;
	private final ArrayList<Tuple> rightBuffer;

	private final String leftColumn;
	private final String rightColumn;
	private int leftCursor;
	private int rightCursor;

	public LeftJoin(final Operator leftOp, final String leftColumn, final Operator rightOp, final String rightColumn) {

		this.leftColumn = leftColumn;
		this.rightColumn = rightColumn;
		this.leftBuffer = new ArrayList<Tuple>();
		this.rightBuffer = new ArrayList<Tuple>();

		while (leftOp.moveNext()) {
			leftBuffer.add(leftOp.current());
		}
		while (rightOp.moveNext()) {
			rightBuffer.add(rightOp.current());
		}

	}

	private final boolean accept(final Tuple leftTuple, Tuple rightTuple) {
		return leftTuple.get(this.leftColumn).equals(rightTuple.get(this.rightColumn));
	}

	@Override
	public boolean moveNext() {

		// some abuse of "for" loop, but somehow nice...
		for (; leftCursor < leftBuffer.size(); rightCursor = 0, leftCursor++) {
			int startedAt = rightCursor;
			while (rightCursor < rightBuffer.size()) {
				Tuple leftTuple = leftBuffer.get(leftCursor);
				// following can be done, because of semantincs of
				// rightCursor++,
				// rightCursor is accessed only once and rightCursor has to be
				// increased in each of the following cases
				Tuple rightTuple = rightBuffer.get(rightCursor++);
				if (accept(leftTuple, rightTuple)) {
					// construct new Tuple
					List<String> colNamesList = new ArrayList<String>(leftTuple.getSchema().getColumnNames().size()
							+ rightTuple.getSchema().getColumnNames().size());

					colNamesList.addAll(leftTuple.getSchema().getColumnNames());
					colNamesList.addAll(rightTuple.getSchema().getColumnNames());

					List<String> values = new ArrayList<String>(leftTuple.getValues().size() + rightTuple.getValues().size());
					values.addAll(leftTuple.getValues());
					values.addAll(rightTuple.getValues());

					current = new Tuple(new TupleSchema(colNamesList), values);
					// finished constructing new tuple
					return true;
				}
			}
			if (startedAt == 0) {
				// the above loop never found a right Tuple, so we have to put
				// the current leftTuple to the result + some empty values
				current = leftBuffer.get(leftCursor);
				return true;
			}
		}
		return false;
	}
}
